package com.lu.barcode

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.util.Size
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import com.google.common.util.concurrent.ListenableFuture
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
import com.lu.barcode.common.BeepManager
import com.lu.barcode.databinding.ActivityScanningBinding
import java.util.concurrent.Executors

/**
 * author: luqihua
 * date:2023/4/6
 * description:
 **/
class ScanningActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "ScanningActivity"
        private val REQUIRED_PERMISSIONS =
            arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
    }

    private lateinit var binding: ActivityScanningBinding

    private val cameraProviderFuture: ListenableFuture<ProcessCameraProvider> by lazy {
        ProcessCameraProvider.getInstance(this)
    }
    private var cameraProvider: ProcessCameraProvider? = null
    private lateinit var mImageAnalysis: ImageAnalysis
    private val mMainExecutor by lazy { ContextCompat.getMainExecutor(this) }

    // 图片分析线程池
    private val mAnalysisExecutor by lazy { Executors.newSingleThreadExecutor() }

    /**
     * 获取摄像头预览useCase
     */
    private val mPreview = Preview.Builder().build()

    private var mBeepAble = false
    private val mBeepManager by lazy { BeepManager(this) }

    private val mPermissionRequest =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            if (permissions.all { it.value }) {
                startCamera()
            } else {
                Toast.makeText(this, "Permissions deny", Toast.LENGTH_SHORT).show()
                finish()
            }
        }

    /**
     * 图片选择结果回调
     */
    private val mOpenAlbumRequest =
        registerForActivityResult(ActivityResultContracts.GetContent()) {
            it?.let {
                val inputImage: InputImage = InputImage.fromFilePath(this, it)
                ScannerAnalyser.scanning(inputImage, successListener = ::onScanSuccess)
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        intent?.getBooleanExtra(BarcodeScanHelper.EXTRA_SCAN_BEEP, false)?.let { mBeepAble = it }
        binding = ActivityScanningBinding.inflate(layoutInflater).apply {
            btnOpenAlbum.setOnClickListener {
                stopScanning()
                mOpenAlbumRequest.launch("image/*")
            }
        }
        setContentView(binding.root)
        checkCamera()
    }

    override fun onDestroy() {
        super.onDestroy()
        cameraProvider?.unbindAll()
    }

    private fun checkCamera() {
        // Request camera permissions
        if (allPermissionsGranted()) {
            startCamera()
        } else {
            mPermissionRequest.launch(REQUIRED_PERMISSIONS)
        }
    }

    private fun startCamera() {
        cameraProviderFuture.addListener({
            cameraProvider = cameraProviderFuture.get()
            bindPreview(cameraProvider)
        }, mMainExecutor)
    }

    /**
     * 开始预览并扫码
     */
    private fun bindPreview(processCameraProvider: ProcessCameraProvider?) {
        processCameraProvider?.let { cameraProvider ->
            mPreview.setSurfaceProvider(binding.pvCameraX.surfaceProvider)
            val width = binding.pvCameraX.width
            val height = binding.pvCameraX.height
            Log.d(TAG, "bindPreview : ${width}x${height}")
            // 设置预览组件
            // 图片分析接口
            mImageAnalysis = ImageAnalysis.Builder()
                // 设置输出图片的旋转角度，这个属性经测试无效
//                    .setTargetRotation(Surface.ROTATION_0)
                // 设置输出图片的分辨率和组件的大小一致
                .setTargetResolution(Size(width, height))
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build()
            startScanning()
            // 使用后置摄像头
            val cameraSelector = CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build()

            cameraProvider.unbindAll()
            // 重新绑定预览useCase，分析useCase
            cameraProvider.bindToLifecycle(this, cameraSelector, mPreview, mImageAnalysis)
            // 确定已经打开过摄像头了
        }

    }

    private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
        ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
    }


    @SuppressLint("UnsafeOptInUsageError")
    private fun startScanning() {
        mImageAnalysis.clearAnalyzer()
        mImageAnalysis.setAnalyzer(mAnalysisExecutor) { imageProxy ->
            val image = imageProxy.image
            if (image == null) {
                Log.d(TAG, "scanBarcodes : image is null")
                return@setAnalyzer
            }
            val inputImage = InputImage.fromMediaImage(image, imageProxy.imageInfo.rotationDegrees)
            ScannerAnalyser.scanning(inputImage,
                successListener = ::onScanSuccess,
                failureListener = ::onScanFailure,
                completeListener = {
                    imageProxy.close()
                })
        }
    }

    private fun onScanSuccess(barcode: Barcode) {
        if (mBeepAble) {
            mBeepManager.playBeepSoundAndVibrate()
        }
        setResult(
            Activity.RESULT_OK,
            Intent().putExtra(BarcodeScanHelper.EXTRA_SCAN_RESULT, barcode.rawValue))
        stopScanning()
        finish()
    }

    private fun onScanFailure(exception: Exception) {
        setResult(
            Activity.RESULT_CANCELED,
            Intent().putExtra(BarcodeScanHelper.EXTRA_SCAN_ERROR, exception.message))
        stopScanning()
        finish()
    }

    private fun stopScanning() {
        mImageAnalysis.clearAnalyzer()
    }
}